﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using psafth.RCTiming.Common;

namespace psafth.RCTiming.Main
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MulticastThread _multicastThread;

        public DBContext DbContext
        {
            get;
            set;
        }

        public MainWindow(DBContext db)
        {
            EventManager.RegisterClassHandler(typeof(Window), Keyboard.KeyDownEvent, new KeyEventHandler(keyDown), true);

            DbContext = db;

            InitializeComponent();

            _multicastThread = new MulticastThread("239.0.0.222", 2222);

            _multicastThread.RunWorkerAsync();

            MainFrame.NavigationUIVisibility = NavigationUIVisibility.Hidden;

            MainFrame.Navigate(new Pages.StartPage());
        }

        /// <summary>
        /// Send an object to the multicast stream to be received by any receivers.
        /// </summary>
        /// <param name="obj"></param>
        public void SendToMulticastThread(object obj, MulticastDataType type)
        {
            try
            {
                switch (type)
                {
                    case MulticastDataType.HeatObject:

                        Heat heat = (Heat)obj;

                        string heatTitle = string.Empty;

                        if (heat.Event != null)
                        {
                            heatTitle = string.Format("{0} | {1} - {2}", heat.Event == null ? "" : heat.Event.EventName, heat.RaceClass == null ? "" : heat.RaceClass.Name, heat.Name);
                        }
                        else
                        {
                            heatTitle = heat.Name;
                        }

                        MCHeat mcHeat = new MCHeat() { Title = heatTitle, Duration = heat.Duration, TimeElapsed = TimeSpan.Parse(heat.Elapsed ?? "0"), IsRunning = heat.IsRunning };
                        heat.HeatCompetitors.ToList().ForEach(hc =>
                        {
                            mcHeat.Competitors.Add(new MCDriver() { BestLapTime = hc.BestLapTime, Name = string.IsNullOrWhiteSpace(hc.FullName) ? "Okänd" : hc.FullName, BoatNumber = hc.StartNumber, FinishTime = hc.FinishTime, IsFinished = hc.IsFinished, LastLapTime = hc.PreviousLap != null ? hc.PreviousLap.LapTime : 0.0, ClubName = hc.ClubName, NumberOfLaps = hc.Laps.Count(l => l.IsValid), Position = hc.Position });
                        });


                        HeatCommand heatCmd = new HeatCommand() { Heat = mcHeat };

                        _multicastThread.Send(heatCmd, type);

                        break;

                    case MulticastDataType.Start:
                        _multicastThread.Send(obj, type);
                        break;

                    case MulticastDataType.Competitors:

                        List<MCDriver> competitors = new List<MCDriver>();

                        ObservableCollectionExt<HeatCompetitor> heatCompetitors = (ObservableCollectionExt<HeatCompetitor>)obj;

                        heatCompetitors.ToList().ForEach(hc =>
                        {
                            competitors.Add(new MCDriver() { BestLapTime = hc.BestLapTime, Name = string.IsNullOrWhiteSpace(hc.FullName) ? "Okänd" : hc.FullName, BoatNumber = hc.StartNumber, FinishTime = hc.FinishTime, IsFinished = hc.IsFinished, LastLapTime = hc.PreviousLap != null ? hc.PreviousLap.LapTime : 0.0, ClubName = hc.ClubName, NumberOfLaps = hc.Laps.Count(l => l.IsValid), Position = hc.Position });
                        });

                        _multicastThread.Send(competitors, type);

                        break;

                    case MulticastDataType.Pause:

                        TimeSpan durationLeft = (TimeSpan)obj;
                        _multicastThread.Send(new PauseCommand() { HeatDurationLeft = durationLeft }, type);
                        break;

                    case MulticastDataType.Stop:
                        _multicastThread.Send(new StopCommand(), type);
                        break;

                    case MulticastDataType.NoRace:
                        _multicastThread.Send(string.Empty, type);
                        break;
                }

            }
            catch (Exception)
            {
                // Fetch everything.
            }
        }

        public void SetAllNavigationButtons(bool enabled)
        {
            btnDecoderSettings.IsEnabled = enabled;
            btnEvent.IsEnabled = enabled;
            btnGeneralSettings.IsEnabled = enabled;
            btnManageDrivers.IsEnabled = enabled;
            btnManageEvents.IsEnabled = enabled;
            btnQuickStart.IsEnabled = enabled;
            btnTraining.IsEnabled = enabled;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void keyDown(object sender, KeyEventArgs e)
        {
            bool modifierKey = (Keyboard.Modifiers == ModifierKeys.Control);

            switch (e.Key)
            {
                case Key.F1:
                    ManualCount(1, modifierKey);
                    break;
                case Key.F2:
                    ManualCount(2, modifierKey);
                    break;
                case Key.F3:
                    ManualCount(3, modifierKey);
                    break;
                case Key.F4:
                    ManualCount(4, modifierKey);
                    break;
                case Key.F5:
                    ManualCount(5, modifierKey);
                    break;
                case Key.F6:
                    ManualCount(6, modifierKey);
                    break;
                case Key.F7:
                    ManualCount(7, modifierKey);
                    break;
                case Key.F8:
                    ManualCount(8, modifierKey);
                    break;
                case Key.F9:
                    ManualCount(9, modifierKey);
                    break;
                case Key.System:
                    if (e.SystemKey == Key.F10)
                    {
                        ManualCount(10, modifierKey);

                        e.Handled = true;
                    }
                    break;
                case Key.F11:
                    ManualCount(11, modifierKey);
                    break;
                case Key.F12:
                    ManualCount(12, modifierKey);
                    break;
            }
        }

        private void ManualCount(int boatNumber, bool countDown)
        {
            object page = this.MainFrame.Content;
            if (page.GetType().Equals(typeof(Pages.RacePage)))
            {
                Pages.RacePage p = (Pages.RacePage)page;

                p.DoManualCountByBoatNumber(boatNumber, countDown);
            }
        }

        public void ManualCount(int? transponderId, bool countDown, bool isPenalty)
        {
            object page = this.MainFrame.Content;
            if (page.GetType().Equals(typeof(Pages.RacePage)))
            {
                Pages.RacePage p = (Pages.RacePage)page;

                p.DoManualCount(transponderId, countDown, isPenalty);
            }
        }

        public void ManualCount(string licenceNumber, bool countDown, bool isPenalty)
        {
            object page = this.MainFrame.Content;
            if (page.GetType().Equals(typeof(Pages.RacePage)))
            {
                Pages.RacePage p = (Pages.RacePage)page;

                p.DoManualCount(licenceNumber, countDown, isPenalty);
            }
        }

        private void ClearHistory()
        {
            if (!this.MainFrame.CanGoBack && !this.MainFrame.CanGoForward)
            {
                return;
            }

            var entry = this.MainFrame.RemoveBackEntry();
            while (entry != null)
            {
                entry = this.MainFrame.RemoveBackEntry();
            }
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {

        }

        private void btnManageEvents_Click(object sender, RoutedEventArgs e)
        {
            ClearHistory();
            MainFrame.Navigate(new Pages.EventPage(this));
            SendToMulticastThread(string.Empty, MulticastDataType.NoRace);
        }

        private void btnDecoderSettings_Click(object sender, RoutedEventArgs e)
        {
            ClearHistory();
            MainFrame.Navigate(new Pages.SettingsDecoder());
            SendToMulticastThread(string.Empty, MulticastDataType.NoRace);
        }

        private void btnQuickStart_Click(object sender, RoutedEventArgs e)
        {
            ClearHistory();
            SendToMulticastThread(string.Empty, MulticastDataType.NoRace);
            MainFrame.Navigate(new Pages.RacePage(this));
        }

        private void btnManageDrivers_Click(object sender, RoutedEventArgs e)
        {
            ClearHistory();
            MainFrame.Navigate(new Pages.UserPage(this));
            SendToMulticastThread(string.Empty, MulticastDataType.NoRace);
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            if (MessageBox.Show("Vill du avsluta? Eventuellt pågående race avslutas.", "Avsluta", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No) == MessageBoxResult.Yes)
            {
                e.Cancel = false;

                ClearHistory();

                SendToMulticastThread(null, MulticastDataType.NoRace);

                if (DbContext != null)
                {
                    DbContext.Dispose();
                    DbContext = null;
                }

                base.OnClosing(e);

            }
            else
            {
                e.Cancel = true;
            }
        }

        private void btnGeneralSettings_Click(object sender, RoutedEventArgs e)
        {
            ClearHistory();
            MainFrame.Navigate(new Pages.SettingsGeneral());
            SendToMulticastThread(string.Empty, MulticastDataType.NoRace);
        }

        private void btnTraining_Click(object sender, RoutedEventArgs e)
        {
            ClearHistory();
            MainFrame.Navigate(new Pages.PracticePage());
            SendToMulticastThread(string.Empty, MulticastDataType.NoRace);
        }
    }
}
